热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

可能会|发生_测试CPythonJava等16种编程语言的HelloWorld:7种存在Bug?

篇首语:本文由编程笔记#小编为大家整理,主要介绍了测试 CPythonJava 等 16 种编程语言的 Hello World:7 种存在 Bug?相关的知识,希望对你有一定的参考价值。 译者 |

篇首语:本文由编程笔记#小编为大家整理,主要介绍了测试 CPythonJava 等 16 种编程语言的 Hello World:7 种存在 Bug?相关的知识,希望对你有一定的参考价值。



译者 | 张洁


责编 | 屠敏


出品 | 程序人生 (ID:coder _life)


Hello World 可能是最常用的计算机程序。几十年来,许多人在开始使用新的编程语言时,编写的第一个程序通常是 Hello World 。


这不起眼的入门程序没有 bug,对吗?



图片来自 sunfishcode 的博客


毕竟,Hello World 程序只做一件事。怎么会有 Bug?


万万没想到,有开发者在好奇心驱动下,测试了 16 种常用的语言后,竟然在里面检测出了 7 种编程语言的 Hello World 带有 Bug。




以 C 语言中的 Hello World 程序为例  


首先,以 C 语言为例来测试。事实上,用 C 语言写 Hello World 有很多不同的版本,如维基百科搜索显示的版本、《C 程序设计语言》(也简称 K&R)一书中的 Hello World,甚至还有从 1974 年贝尔实验室备忘录中引入的最古老的 C 语言 Hello World 程序。



图片来自 sunfishcode 的博客


这是 "ANSI C "(美国国家标准协会和国际标准化组织对 C 语言发布的标准)中的 Hello World 程序写法:


/* Hello World in C, Ansi-style */
#include
#include
int main(void)
puts("Hello World!");
return EXIT_SUCCESS;

对于业界而言,这应该是最标准 C 语言 Hello World 的版本。


它使用“(void)”来显示 main 是一种新型声明方式。这个版本使用 EXIT_SUCCESS 返回值来表示成功,而不是使用 0。根据 C 语言标准,这其实没有必要,不过在此我们也不做更改了。除此之外,它还使用了适当的头文件声明了 puts 函数。


这个版本试图把所有的步骤都做到完美。


然而,它里面还是有一个 Bug。




C 语言中的 Bug 从何而来?


Linux 有一个有趣的设备文件,叫做“/dev/full”,跟“/dev/null”(程序员群体中行话叫做黑洞,即丢弃一切写入其中的数据,读取它会立即得到一个 EOF)非常像,但是当你将数据写入到“/dev/full”时,该文件不会扔掉数据,而会出现错误。它的作用就像是文件系统中一个刚刚用完空间的文件:


$ echo "Hello World!" > /dev/full
bash: echo: write error: No space left on device
$ echo $?
1

因此用这个文件可以用来测试程序是否正确处理 I/O 错误。创建没有剩余空间的实际文件系统或实际发生故障的磁盘很不方便,但要求程序将其输出写入“/dev/full”文件中,看看会发生什么吧。


所以让我们测试一下上面的 C 语言示例:


$ gcc hello.c -o hello
$ ./hello > /dev/full
$ echo $?
0

与我们在上面的 shell 脚本中使用 echo 时不同,在这里,我们没有得到任何输出的内容,返回值为 0。这意味着 Hello World 程序执行成功了。


然而,它实际上并没有成功。我们可以使用 strace 进行确认:


$ strace -etrace=write ./hello > /dev/full
write(1, "Hello World!\\n", 13) = -1 ENOSPC (No space left on device)
+++ exited with 0 +++

操作系统提示了 "No space"错误。但是,程序还是成功执行了,并返回值为 0,这以为系统认为这一段代码是成功的。显而易见,这是一个 Bug!


那么,这个 Bug 有多严重呢?


可以说,Hello World 不应该作为标准的测试代码,因为它并不是绝对的安全。


此话应该从何说起?想必很多程序员在初次学习编程的时候,大多数会用 Hello World 程序来试一下。这也导致了 Hello World 常被开发者用来检测程序的标准输出,但是因为此时 Hello World 程序存在 Bug,所以 prints 的标准输出往往可能会被重定向到另一个文件。


譬如,现实世界中,如果文件占用了全部的空间。此时用 Hello World 程序来检测,最终并没有检测任何问题,那么该代码的父进程将不知道子进程失败了,会继续运行,即使系统期望产生的输出内容已经悄悄地丢失了数据,但程序还是像什么都没有发生一样。


举个例子,编写一个程序,其中主要是 prints 一个 yaml 文件到标准输出。如果标准输出的空间用完了,输出可能会在某个任意的点被截断,尽管它仍是有效的 yaml。所以我们期望程序能够检测并报告这种情况。




7 种主流语言常见的 Hello World 程序都有 Bug?


除了 C 语言之外,Python 告诉我们“Bug 不应该被无声地忽视”,下面是 Python 2 的测试示例:


$ python2 hello.py > /dev/full
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
$ echo $?
0

它确实向 stderr 输出了一条信息,并且还是一条令人困惑的信息。然而,它也返回了 0,这意味着它在告诉运行它的人,它成功退出了。


幸运的是,Python 3 正确地报告了错误,而且还显示了一个更漂亮的错误信息。


$ python3 hello.py > /dev/full
Exception ignored in: <_io.TextIOWrapper name&#61;&#39;&#39; mode&#61;&#39;w&#39; encoding&#61;&#39;utf-8&#39;>
OSError: [Errno 28] No space left on device
$ echo $?
120

另外&#xff0c;我也还是使用普通教程网站上的 Hello World 程序&#xff0c;尝试了其他几种编程语言&#xff0c;以下是测试结果&#xff1a;


语言

是否有bug

测试的版本

C

(全部)

C&#43;&#43;

(全部)

Python 2

 是

Python 2.7.18

Ruby

ruby 2.7.2p137&#xff08;2020-10-01 修订版 5445e04352&#xff09;[x86_64-linux-gnu]

Java

openjdk 11.0.11 2021-04-20

Node.js

v12.21.0

Haskell

Glorious Glasgow Haskell 编译系统&#xff0c;版本 8.8.4

Rust

rustc 1.59.0 (9d1b2106e 2022-02-23)

Python 3

Python 3.9.5

Perl

perl 5&#xff0c;版本 32&#xff0c;subversion 1 (v5.32.1) 为 x86_64-linux-gnu-thread-multi 构建&#xff08;带有 46 个注册补丁...&#xff09;

Perl 6

v2020.12

Bash

GNU bash&#xff0c;版本 5.1.4(1)-release (x86_64-pc-linux-gnu)

Awk

GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)

OCaml

4.08.1

Tcl

8.6.11

C#

Mono JIT 编译器版本 6.8.0.105


原文链接&#xff1a;https://blog.sunfishcode.online/bugs-in-hello-world/


声明&#xff1a;本文为 CSDN 翻译&#xff0c;转载请注明来源。



《新程序员001-003》全面上市&#xff0c;对话世界级大师&#xff0c;报道中国IT行业创新创造&#xff01;








☞厌倦了“复制粘贴”&#xff0c;我辞去了年薪45万美元的开发工作




☞机器人操控电脑&#xff0c;华为天才少年稚晖君再出手&#xff0c;直呼&#xff1a;项目不太难&#xff01;


☞阿里、腾讯基本薪资曝光&#xff0c;资深算法工程师24万美元&#xff0c;高级研究员26万美元

推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文介绍了Python对Excel文件的读取方法,包括模块的安装和使用。通过安装xlrd、xlwt、xlutils、pyExcelerator等模块,可以实现对Excel文件的读取和处理。具体的读取方法包括打开excel文件、抓取所有sheet的名称、定位到指定的表单等。本文提供了两种定位表单的方式,并给出了相应的代码示例。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
author-avatar
罂粟花很美也需要阳光
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有